package org.ne.springboot.utils.PaperHandleUtils.StructCheckUtils;


import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.json.JSONObject;
import org.ne.springboot.utils.PaperHandleUtils.PaperContentCheckUtils.SparkClient;
import org.ne.springboot.utils.PaperHandleUtils.AbstractTranslateCheckUtils.TranslateCheckUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wey
 */
@Slf4j
public class StructCheckUtils {


    // 字数计算

    public static int calculateWord(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }

        int textSum = 0;
        StringBuilder stack = new StringBuilder();
        for (char c : text.toCharArray()) {

            if (c >= 32 && c <= 126) {
                if (!Character.isWhitespace(c)) {
                    stack.append(c);
                } else if (!stack.isEmpty() && stack.charAt(stack.length() - 1) != ' ') {
                    stack.append(' ');
                }
            } else {
                if (!stack.isEmpty() && stack.charAt(stack.length() - 1) != ' ') {
                    stack.append(' ');
                }
                textSum++;
            }
        }

        if (!stack.isEmpty() && stack.charAt(stack.length() - 1) == ' ') {
            stack.setLength(stack.length() - 1);
        }

        if (!stack.isEmpty()) {
            textSum += stack.toString().split("\\s+").length;
        }

        return textSum;
    }

    // 计算字数、表格数和图片数
    public static int[] calculateWordTableAndFigureNum(XWPFDocument docx) {
        int textSum = 0;
        int tableNum = 0;
        int figureNum = 0;

        // 统计段落文字
        for (XWPFParagraph paragraph : docx.getParagraphs()) {
            textSum += calculateWord(paragraph.getText());
        }

        // 统计图片
        for (XWPFPictureData picture : docx.getAllPictures()) {
            figureNum++;
        }

        // 统计表格文字
        for (XWPFTable table : docx.getTables()) {
            tableNum++;
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    textSum += calculateWord(cell.getText());
                }
            }
        }

        return new int[]{textSum, tableNum, figureNum};
    }

    // 按一级标题分割文档

    /**
     * 将文档按一级标题分割为文本段落。
     *
     * @param docx 论文文档
     * @return 返回以一级标题为分割的文本列表
     */
    public static List<String> divideDocxByHeading1(XWPFDocument docx) {
        if (docx == null) {
            return new ArrayList<>();
        }
        List<String> texts = new ArrayList<>();
        StringBuilder text = new StringBuilder();
        //boolean isCatalog = false;
        XWPFStyles styles = docx.getStyles();

        int n = 0;
        boolean isContent = false;
        for (XWPFParagraph paragraph : docx.getParagraphs()) {
            if(paragraph.getText().isEmpty()) {
                continue;
            }
            //System.out.println(n+paragraph.getText()+"    @@@@     ");n++;

            String paraText = paragraph.getText().trim();

            if (!isContent && paraText.contains("致") && paraText.contains("谢")) {
                isContent = true;
                continue;
            }
            if (!isContent) {
                continue;
            }

            if (isHeading1(paragraph, styles)) {
                if (!text.isEmpty()) {
                    texts.add(text.toString());
                    text = new StringBuilder();
                }
            }
            text.append(paraText).append("\n");
        }

        if (!text.isEmpty()) {
            texts.add(text.toString());
        }

        if (!texts.isEmpty() && texts.size() > 1) {
            try {
                String abstractText = extractAbstract(texts.get(1));
                texts.set(1, abstractText);
            } catch (Exception e) {
//                System.err.println("摘要提取失败: " + e.getMessage());
                // 保留原始文本作为后备
                log.error("摘要提取失败");
            }
        }

        return texts;
    }

    private static boolean isHeading1(XWPFParagraph paragraph, XWPFStyles styles) {

        if (paragraph == null) {
            return false;
        }

        Pattern headingPattern = Pattern.compile("(heading|标题)\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
        Pattern digitalPattern = Pattern.compile("(\\d+)");

        String styleID = paragraph.getStyleID();
        String styleName = null;
        Integer level = null;
        //System.out.println("styleID: " + styleID+paragraph.getText());

        // 1. 优先通过样式表解析样式名称
        if (styles != null && styleID != null) {
            XWPFStyle style = styles.getStyle(styleID);
            if (style != null) {
                styleName = style.getName();
            }
        }

        // 2. 基于样式名称判断是否为标题并提取层级
        if (styleName != null) {
            String lowerStyleName = styleName.toLowerCase();
            Matcher headingMatcher = headingPattern.matcher(lowerStyleName);

            // 情况A: 样式名明确匹配 "heading {数字}" 或 "标题{数字}"
            if (headingMatcher.find()) {
                // 提取数字部分
                String numStr = headingMatcher.group(2);
                try {
                    level = Integer.parseInt(numStr);
                } catch (NumberFormatException e) {
                    // 理论上不会发生，因正则已匹配数字
                    level = null;
                }
            }
            // 情况B: 样式名可能包含其他形式的数字（如"MyStyle-1"）
            else {
                Matcher digitalMatcher = digitalPattern.matcher(styleName);
                if (digitalMatcher.find()) {
                    try {
                        int extractedNum = Integer.parseInt(digitalMatcher.group(1));
                        // 合理层级范围
                        if (extractedNum >= 1 && extractedNum <= 9) {
                            level = extractedNum;
                        }
                    } catch (NumberFormatException e) {
                        level = null;
                    }

                }

            }
            // 情况C: 样式名表明是标题但无法解析层级（如"Title"）
            if (level == null && (lowerStyleName.contains("heading") || lowerStyleName.contains("标题"))) {
                level = -1;
                // 标记为未知层级

            }
        }

        if (level == null) { return false;}
        return level == 1;

    }



    // 提取摘要（到“关键词”前）
    private static String extractAbstract(String text) {
        String[] lines = text.split("\n");
        StringBuilder abstractText = new StringBuilder();
        for (String line : lines) {
            abstractText.append(line).append("\n");
            if (line.trim().startsWith("关键词")) {
                break;
            }
        }
        return abstractText.toString();
    }




    // 生成报告
    public static XWPFDocument output(List<JSONObject> resText, String structEvaluation, String workloadCheck) throws IOException {


        if (resText == null || structEvaluation == null || workloadCheck == null) {
            throw new IllegalArgumentException("参数不能为 null");
        }

        XWPFDocument out = new XWPFDocument();

        XWPFParagraph heading = out.createParagraph();
        XWPFRun headingRun = heading.createRun();
        headingRun.setText("论文结构检查");
        headingRun.setBold(true);
        headingRun.setFontSize(16);

        int cnt = 0;
        for (JSONObject item : resText) {
            XWPFParagraph subHeading = out.createParagraph();
            XWPFRun subHeadingRun = subHeading.createRun();
            subHeadingRun.setText("结构" + (cnt + 1));
            subHeadingRun.setBold(true);
            subHeadingRun.setFontSize(14);
            cnt++;

            XWPFParagraph structPara = out.createParagraph();
            XWPFRun structRun = structPara.createRun();
            structRun.setText("结构所属：" + item.optString("struct", "未知"));

            XWPFParagraph analysisPara = out.createParagraph();
            XWPFRun analysisRun = analysisPara.createRun();
            analysisRun.setText("分析：" + item.optString("msg", "未知"));

        }

        // 添加总体结构评价
        out.createParagraph(); // 空段落作为分隔
        XWPFParagraph evalPara = out.createParagraph();
        XWPFRun evalRun = evalPara.createRun();
        evalRun.setText("结论: ");
        evalRun.setBold(true);
        evalRun.setFontSize(14);

        XWPFRun evalRun1 = evalPara.createRun();
        evalRun1.setText(structEvaluation);

        // 添加工作量检查
        XWPFParagraph workloadHeading = out.createParagraph();
        XWPFRun workloadRun = workloadHeading.createRun();
        workloadRun.setText("论文工作量检查");
        workloadRun.setBold(true);
        workloadRun.setFontSize(16);

        XWPFParagraph workloadPara = out.createParagraph();
        XWPFRun workloadRun2 = workloadPara.createRun();
        workloadRun2.setText(workloadCheck);


        return out;
    }

    // 主流程
    public static XWPFDocument structCheckByAI(HttpServletResponse httpServletResponse, MultipartFile file, String model) throws IOException {
        log.debug("开始格式检查, 文件名={}", file == null ? "null" : file.getOriginalFilename());
        httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        httpServletResponse.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode("结构检查报告.docx", StandardCharsets.UTF_8));
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        XWPFDocument doc = null;
        try (InputStream is = file.getInputStream()) {
            doc = new XWPFDocument(is);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<String> texts = divideDocxByHeading1(doc);
        if (texts.isEmpty()) {
            throw new IOException("无法分割文档内容");
        }

        String prompt = "作为专业的论文审批教授，分析给出的文章最可能属于摘要、引言或者绪论、需求分析或者系统分析、系统设计、系统实现、系统测试等（系统测试也可包含在系统实现部分中）的哪一部分，并说明原因及该部分工作量是否合适，其中摘要不低于200字；引言或者绪论部分不应少于800字，否则提示“引言中题目的背景、必要性以及相关意义描述过于简单”、 需求分析篇幅不等少于2页，否则提示需求分析不完备，过于简单。系统设计、系统实现、系统测试等相关内容篇幅不低于论文总篇幅的60%， 否则给出相应提示。系统设计篇幅不少于2页，系统实现不少于4页，否则给出相应提示，以严格JSON格式返回，除json内容外无其他内容，其中包含字段struct表明该段文章属于论文的哪个部分,msg字段表明其属于该部分的原因及工作量分析。 ";

        HashMap<String, Object> format = new HashMap<>();

        SparkClient sparkClient = new SparkClient();
        format.put("struct", "所属的部分");
        format.put("msg", "原因及工作量分析");
        sparkClient.setFormat(format);
        sparkClient.setModel(model);

        List<JSONObject> resText = new ArrayList<>();

        StringBuilder text1 = new StringBuilder();
        if (doc != null) {
            for (int i : Translate_divideDocxByHeading1(doc)) {
                text1.append(Arrays.toString(Translate_getTextFromAbstractToKey(i, doc)));
            }
        }
        Map<String, Object> result = sparkClient.processRequest(prompt, text1.toString());
        if ("success".equals(result.get("status"))) {
            Map<String, Object> answer = (Map<String, Object>) result.get("answer");
            JSONObject response = new JSONObject()
                    .put("struct", answer.get("struct"))
                    .put("msg", answer.get("msg"));
            resText.add(response);
        } else {
            throw new IllegalArgumentException((String) result.get("message"));
        }
        // 分析段落
//        System.out.println(texts.size());
//        log.debug("texts.size()={}" , texts.size());
        for (int i = 0; i < texts.size(); i++) {
//            System.out.println(i);
            result = sparkClient.processRequest(prompt, texts.get(i));
            if ("success".equals(result.get("status"))) {
                @SuppressWarnings("unchecked")
                Map<String, Object> answer = (Map<String, Object>) result.get("answer");
                JSONObject response = new JSONObject()
                        .put("struct", answer.get("struct"))
                        .put("msg", answer.get("msg"));
                resText.add(response);
            } else {
                throw new IllegalArgumentException((String) result.get("message"));
            }
        }



        // 修改 prompt2 以匹配新的数据结构
        String prompt2 = "作为专业的论文审批教授，请分析以下论文结构数据（包含在 'sections' 属性中）：\n" +
                "一个论文的总体结构应该包含摘要、引言或者绪论、需求分析或者系统分析、系统设计、系统实现、系统测试等（系统测试也可包含在系统实现部分中）。\n" +
                "根据提供的数据分析其缺少哪一部分，或者存不存在结构问题或结构混乱。并以文本形式返回客观的评价";
        JSONObject wrapper = new JSONObject();
        wrapper.put("sections", resText);
        result = sparkClient.processRequest(prompt2, wrapper.toString());

        String structEvaluat = "";
        if ("success".equals(result.get("status"))) {
            Map<String, Object> answer = (Map<String, Object>) result.get("answer");
            structEvaluat = (String) answer.get("msg");
        } else {
//            System.out.println(result.get("msg"));
            log.debug("结构错误信息 {}",result.get("msg").toString());
        }

        int[] stats = calculateWordTableAndFigureNum(doc);
        int textSum = stats[0];
        int tableNum = stats[1];
        int figureNum = stats[2];

        String workloadCheck = (textSum >= 8000 && tableNum + figureNum >= 10) ? "论文工作量达标" : "论文工作量较低";
//        System.out.println("workloadCheck" + workloadCheck);
//        System.out.println("structCheck" + structEvaluat);
        XWPFDocument out = output(resText, structEvaluat, workloadCheck);
        log.debug("结构检查完成");
        doc.close();
        return out;
    }


        //divide_docx_by_heading_1
    public static List<Integer> Translate_divideDocxByHeading1(XWPFDocument docx) {
        List<Integer> headList = new ArrayList<>();

        for (int i = 0; i < docx.getParagraphs().size(); i++) {
            if (headList.size() == 2) {
                break;
            }

            XWPFParagraph paragraph = docx.getParagraphs().get(i);
            String text = paragraph.getText().replace("\n", "").replace("\t", "").replace(" ", "");

            if (text.equals("摘要") || text.equals("Abstract")) {
                headList.add(i);
            }
        }
        return headList;
    }

    //get_text_from_abstract_2_key
    public static Object[] Translate_getTextFromAbstractToKey(int index, XWPFDocument docx) {
        StringBuilder text = new StringBuilder();
        boolean found = false;
        List<XWPFParagraph> paragraphs = docx.getParagraphs();
        for (int i = index; i < paragraphs.size(); i++) {
            XWPFParagraph paragraph = paragraphs.get(i);
            text.append(paragraph.getText()).append("\n");

            List<XWPFRun> runs = paragraph.getRuns();
            if (!runs.isEmpty() &&
                    (paragraph.getText().startsWith("Key") || paragraph.getText().startsWith("关键词：")) &&
                    runs.get(0).isBold() &&
                    (i > 0 && paragraphs.get(i - 1).getRuns().isEmpty())) {
                found = true;
                break;
            }
        }
        return new Object[]{text.toString(), found};
    }


}


